#include <memory.h>
#include <iostream>
#include "BitArray.h"

namespace suxw
{
    BitArray::BitArray()
    {
        m_pcBitBuf = 0;
        m_nBitsCount = 0;
    }

    BitArray::BitArray(int nBitsCount)
    {
        int size = calcSize(nBitsCount);
        m_nBitsCount = 0;

        m_pcBitBuf = new unsigned char[size];
        if (m_pcBitBuf)
        {
            memset(m_pcBitBuf, 0, size);
            m_nBitsCount = nBitsCount;
        }
    }

    BitArray::~BitArray()
    {
        if (m_pcBitBuf)
        {
            delete[] m_pcBitBuf;
            m_pcBitBuf = 0;
            m_nBitsCount = 0;
        }
    }

    //get buffer size
    int BitArray::size()
    {
        if (m_pcBitBuf == 0)
        {
            return 0;
        }

        return calcSize(getBitsCount()); 
    }

    //set valid bit count
    bool BitArray::setBitsCount(unsigned int nBitsCount)
    {
        int size = calcSize(nBitsCount);
        
        if (size > this->size())
        {
            if (m_pcBitBuf)
            {
                delete[] m_pcBitBuf;
                m_pcBitBuf = 0;
            }

            m_pcBitBuf = new unsigned char[size];
            memset(m_pcBitBuf, 0, size);
        }
        else
        {
            clear();
        }
        
        m_nBitsCount = nBitsCount;
        return true;
    }

    //get valid bit cout
    unsigned int BitArray::getBitsCount()
    {
        return m_nBitsCount;
    }

    //get buffer of bit array
    unsigned char* BitArray::getBitArray()
    {
        return m_pcBitBuf;
    }

    //clear buffer
    void BitArray::clear()
    {
        if (!m_pcBitBuf)
            return;
        
        memset(m_pcBitBuf, 0, size());
    }

    //calculate buffer size of bit array
    int BitArray::calcSize(unsigned int nBitsCount)
    {
        int size = nBitsCount / 8;
        if (nBitsCount % 8)
        {
            size += 1;
        }

        return size;
    }

    //set bit value, index base on 1
    bool BitArray::setBit(unsigned int index, bool value)
    {
        --index;
        if (index >= getBitsCount())
        {
            return false;
        }
        
        char mask = 0x80 >> (index % 8);
        if (value)
        {
            m_pcBitBuf[index / 8] |= mask;
        }
        else
        {
            mask ^= 0xFF;
            m_pcBitBuf[index / 8] &= mask;
        }

        return true;
    }

    //get bit value, index base on 1
    inline bool BitArray::getBit(unsigned int index)
    {
        --index;
        return (m_pcBitBuf[index / 8] & (0x08 >> (index % 8)));
    }

    //self test function
    bool BitArray::main(int argc, char **argv)
    {
        unsigned char *pcBuf = 0;
        unsigned char szDestBitMap[] = {
            1, 2, 3, 4, 5, 6, 7, 8
        };

        BitArray bitMap(64);
        bitMap.setBit(8, true);
        bitMap.setBit(15, true);
        bitMap.setBit(23, true);
        bitMap.setBit(24, true);
        bitMap.setBit(30, true);
        bitMap.setBit(38, true);
        bitMap.setBit(40, true);
        bitMap.setBit(46, true);
        bitMap.setBit(47, true);
        bitMap.setBit(54, true);
        bitMap.setBit(55, true);
        bitMap.setBit(56, true);
        bitMap.setBit(61, true);
        std::cout << "bitMap bit count = " << bitMap.getBitsCount() << std::endl;
        std::cout << "bitMap size = " << bitMap.size() << std::endl;
        std::cout << "bitMap data" << std::endl;
        pcBuf = bitMap.getBitArray();
        for (int i = 0; i < bitMap.size(); i++)
        {
            std::cout << (int)(pcBuf[i]) << " ";
        }
        std::cout << std::endl;

        if (memcmp(szDestBitMap, pcBuf, bitMap.size()))
        {
            std::cout << "BitArray Test fail, not equal 0102030405060708" << std::endl;
        }
        else
        {
            std::cout << "BitArray Test succ, equal 0102030405060708" << std::endl;
        }

        return true;
    }
}
